home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / util / boot / bind_namesii.lha / BindNamesII.c < prev    next >
C/C++ Source or Header  |  1995-09-14  |  22KB  |  1,027 lines

  1. /* $Header: Src/rcs/BindNamesII.c,v 1.5 1995/06/21 17:24:04 cmh Exp cmh $
  2.  *
  3.  * BindNamesII: Handy assign/path maker.
  4.  * Copyright (C) 1994-95  Magnus Holmgren <cmh@augs.se>
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. #include <exec/types.h>
  22. #include <exec/lists.h>
  23. #include <exec/memory.h>
  24. #include <dos/exall.h>
  25. #include <dos/dosextens.h>
  26.  
  27. #include <clib/alib_protos.h>
  28. #include <clib/dos_protos.h>
  29. #include <clib/exec_protos.h>
  30. #include <clib/utility_protos.h>
  31.  
  32. #ifdef __GNUC__
  33. #include <inline/alib.h>
  34. #include <inline/dos.h>
  35. #include <inline/exec.h>
  36. #include <inline/utility.h>
  37. #endif
  38.  
  39. #include <dos/dos.h>
  40. #include <dos/dostags.h>
  41. #include <dos/rdargs.h>
  42. #include <strings.h>
  43. #include "assignnode.h"
  44.  
  45. #define Prototype extern
  46.  
  47. #include "proto.h"
  48. #include "macros.h"
  49.  
  50.  
  51. /* Program arguments */
  52. struct Flags
  53. {
  54.     STRPTR    Drawer;
  55.     LONG    Test;
  56.     LONG    Verbose;
  57.     LONG    Quiet;
  58.     STRPTR    PathAddChar;
  59.     STRPTR    PathStart;
  60. };
  61.  
  62. #define TEMPLATE "DRAWER,TEST/S,VERBOSE/S,QUIET/S,PATHADDCHAR/K,PATHSTART/K"
  63.  
  64.  
  65. /* Template for an assign in a file */
  66. struct AssignTemplate
  67. {
  68.     STRPTR    Name;
  69.     STRPTR    *Target;
  70.     STRPTR    Alias;
  71.     LONG    *Pri;
  72.     LONG    Defer;
  73.     LONG    Path;
  74.     LONG    Add;
  75.     LONG    PathAdd;
  76. };
  77.  
  78. #define ASSIGNTEMPLATE "NAME/A,TARGET/A/M,ALIAS/K,PRI=PRIORITY/K/N,DEFER/S,PATH/S,ADD/S,PATHADD/S"
  79.  
  80.  
  81. /* Size of read buffer. Lines larger than this are truncated. */
  82. #define READBUF_SIZE    512
  83.  
  84. #ifdef __GNUC__
  85. BYTE __nocommandline = 1;       /* Disable libnix argument parsing */
  86. LONG __osversion = 37;
  87. #endif
  88.  
  89. /* Global variables: */
  90.  
  91. /* If Test is TRUE, then don't do any assigns/mounts/createdirs/pathadds.
  92.  * Assigns (to "known" volumes), createdirs and pathadds are assumed to
  93.  * succeed, while mounts are assumed to fail (since all unresolved
  94.  * volumes are mounted before BindNamesII gives up).
  95.  */
  96. Prototype BOOL Test;
  97. BOOL    Test;
  98.  
  99. /* Don't print the list over failed assigns. */
  100. BOOL    Quiet;
  101.  
  102. /* If TRUE, then output extra "debug" information. */
  103. BOOL    Verbose;
  104.  
  105. /* Path separator used by the PATHADD option */
  106. Prototype TEXT PathAddChar;
  107. TEXT    PathAddChar = '|';
  108.  
  109. /* Name of PathHandler device */
  110. Prototype STRPTR PathStart;
  111. STRPTR    PathStart = "Path:";
  112.  
  113. /* Length of above string */
  114. LONG    PathStartLen = 5;
  115.  
  116. /* End of global variables. */
  117.  
  118.  
  119. #ifdef __GNUC__
  120. STRPTR
  121. stpcpy( STRPTR dest, STRPTR source )
  122. {
  123.     while( ( *dest++ = *source++ ) );
  124.  
  125.     return( dest - 1 );
  126. }
  127. #endif
  128.  
  129.  
  130. /* Read the named file, and add the AssignNodes it contains to the list. */
  131. BOOL
  132. ReadAssignFile( STRPTR name, struct MinList *list )
  133. {
  134.     struct RDArgs    *rdArg;
  135.     BOOL    ret = FALSE;
  136.  
  137.     SetIoErr( 0 );
  138.  
  139.     if( ( rdArg = AllocDosObject( DOS_RDARGS, NULL ) ) )
  140.     {
  141.         BPTR    file;
  142.         TEXT    readBuffer[ READBUF_SIZE + 2 ];
  143.  
  144.         rdArg->RDA_Flags = RDAF_NOPROMPT;
  145.  
  146.         if( ( file = Open( name, MODE_OLDFILE ) ) )
  147.         {
  148.             struct AssignTemplate    flags;
  149.             struct AssignNode    *allocOk = ( struct AssignNode * ) 4;
  150.             LONG    line = 0;
  151.  
  152.             ret = TRUE;
  153.  
  154.             while( allocOk && FGets( file, readBuffer, READBUF_SIZE ) )
  155.             {
  156.                 ++line;
  157.  
  158.                 /* Skip any comments */
  159.                 if( *readBuffer == ';' || *readBuffer == '#' )
  160.                 {
  161.                     continue;
  162.                 }
  163.  
  164.                 /* Prepare for parsing */
  165.                 rdArg->RDA_Source.CS_Buffer = readBuffer;
  166.                 rdArg->RDA_Source.CS_Length = strlen( readBuffer );
  167.                 rdArg->RDA_Source.CS_CurChr = 0;
  168.                 bzero( &flags, sizeof( flags ) );
  169.  
  170.                 if( ReadArgs( ASSIGNTEMPLATE, ( LONG * ) &flags, rdArg ) )
  171.                 {
  172.                     WORD    type = ASN_NORMAL, flag = 0;
  173.                     BYTE    pri = 0;
  174.  
  175.                     if( !Stricmp( flags.Name, "CMDPATH" ) )
  176.                     {
  177.                         type = ASN_CMDPATH;
  178.                     }
  179.                     else if( flags.Path )
  180.                     {
  181.                         type = ASN_PATH;
  182.                     }
  183.                     else if( flags.Defer )
  184.                     {
  185.                         type = ASN_DEFER;
  186.                     }
  187.  
  188.                     if( flags.Add )
  189.                     {
  190.                         flag |= ANF_ADD;
  191.                     }
  192.  
  193.                     if( flags.PathAdd )
  194.                     {
  195.                         flag |= ANF_PATHADD;
  196.                     }
  197.  
  198.                     if( flags.Pri )
  199.                     {
  200.                         pri = *flags.Pri;
  201.  
  202.                         if( ( *flags.Pri > 127 ) || ( *flags.Pri < -128 ) )
  203.                         {
  204.                             Printf( "Prority out of range on line %ld in file \"%s\"\n",
  205.                                 line, name );
  206.                             ret = FALSE;
  207.                         }
  208.                     }
  209.  
  210.                     if( ( type != ASN_CMDPATH ) && !strchr( flags.Name, ':' ) )
  211.                     {
  212.                         Printf( "Colon missing on line %ld in file \"%s\"\n",
  213.                             line, name );
  214.                         ret = FALSE;
  215.                     }
  216.  
  217.                     allocOk = AllocAssignNode(
  218.                         list,
  219.                         flags.Name,
  220.                         flags.Target,
  221.                         pri,
  222.                         flags.Alias,
  223.                         type,
  224.                         flag );
  225.                     FreeArgs( rdArg );
  226.                 }
  227.                 else
  228.                 {
  229.                     PrintError( "Error in line %ld in file \"%s\"", line, name );
  230.                     ret = FALSE;
  231.                 }
  232.             }
  233.  
  234.             if( !allocOk )
  235.             {
  236.                 SetIoErr( ERROR_NO_FREE_STORE );
  237.             }
  238.  
  239.             if( IoErr() )
  240.             {
  241.                 PrintError( "Error reading line %ld in file \"%s\"", line, name );
  242.                 ret = FALSE;
  243.             }
  244.  
  245.             Close( file );
  246.         }
  247.         else
  248.         {
  249.             PrintError( "Couldn't open file \"%s\"", name );
  250.         }
  251.  
  252.         FreeDosObject( DOS_RDARGS, rdArg );
  253.     }
  254.     else
  255.     {
  256.         PrintNoMem();
  257.     }
  258.  
  259.     return( ret );
  260. }
  261.  
  262.  
  263. /* Placed here to save some space. A string merge option in DICE would've been nice.. :) */
  264. const TEXT NoExamine_Msg[] = "Couldn't examine drawer \"%s\"";
  265.  
  266. /* Scan the specified drawer, and call ReadAssignFile() for each file encountered.
  267.  * I haven't bothered to use ExAll() here. We're probably dealing with relatively
  268.  * few files in the drawer (usually less than a dozen), so the code to handle the
  269.  * ExAll() stuff simply isn't worth it. We keep it small instead.
  270.  */
  271. BOOL
  272. ScanDrawer( STRPTR drawer, struct MinList *list )
  273. {
  274.     struct FileInfoBlock    *fib;
  275.     LONG    err = TRUE;
  276.  
  277.     if( ( fib = AllocDosObject( DOS_FIB, NULL ) ) )
  278.     {
  279.         BPTR    lock;
  280.  
  281.         if( ( lock = Lock( drawer, SHARED_LOCK ) ) )
  282.         {
  283.             BPTR    oldLock = CurrentDir( lock );
  284.  
  285.             if( ( Examine( lock, fib ) ) )
  286.             {
  287.                 /* Make sure we've examined a drawer */
  288.                 if( fib->fib_DirEntryType > 0 )
  289.                 {
  290.                     err = FALSE;
  291.  
  292.                     while( ExNext( lock, fib ) )
  293.                     {
  294.                         /* Only process files */
  295.                         if( fib->fib_DirEntryType < 0 )
  296.                         {
  297.                             /* Skip any symbols... */
  298.                             if( Stricmp( fib->fib_FileName + strlen( fib->fib_FileName ) - 5, ".info" ) )
  299.                             {
  300.                                 if( !ReadAssignFile( fib->fib_FileName, list ) )
  301.                                 {
  302.                                     err = TRUE;
  303.                                     break;
  304.                                 }
  305.                             }
  306.                         }
  307.                     }
  308.  
  309.                     if( !err && ( IoErr() != ERROR_NO_MORE_ENTRIES ) )
  310.                     {
  311.                         PrintError( NoExamine_Msg, drawer );
  312.                         err = TRUE;
  313.                     }
  314.                 }
  315.                 else
  316.                 {
  317.                     Printf( "BindNamesII: '%s' is not a drawer\n", drawer );
  318.                 }
  319.             }
  320.             else
  321.             {
  322.                 PrintError( NoExamine_Msg, drawer );
  323.             }
  324.  
  325.             CurrentDir( oldLock );
  326.             UnLock( lock );
  327.         }
  328.         else
  329.         {
  330.             PrintError( NoExamine_Msg, drawer );
  331.         }
  332.  
  333.         FreeDosObject( DOS_FIB, fib );
  334.     }
  335.     else
  336.     {
  337.         PrintNoMem();
  338.     }
  339.  
  340.     return( !err );
  341. }
  342.  
  343.  
  344. /* Check if this nodes parent (or the parents parent, etc.), refer
  345.  * to unknown volumes. All nodes that directly refers to unknown
  346.  * nodes should have the flag ANF_STRAY set, or this function will not
  347.  * behave as it should.. :)
  348.  * If a loop is detected, return -1. Otherwise 1 is returned if a stray node
  349.  * is found, and 0 for no such nodes.
  350.  */
  351. WORD
  352. IsStray( struct AssignNode *node )
  353. {
  354.     WORD    ret = 0;
  355.  
  356.     /* Check for loops. We don't want to overflow the stack just because
  357.      * the user passed in bad data, do we? :)
  358.      */
  359.     if( node->Flags & ANF_VISIT )
  360.     {
  361.         ret = -1;
  362.         node->Flags |= ANF_LOOP;
  363.     }
  364.     else if( node->Flags & ANF_LOOP )    /* Looped node? */
  365.     {
  366.         ret = -1;
  367.     }
  368.     else if( node->Flags & ANF_STRAY )    /* Stray node? */
  369.     {
  370.         ret = 1;
  371.     }
  372.     else
  373.     {
  374.         struct PathNode *pathNode, *next;
  375.  
  376.         /* Indicate that we've visited this node */
  377.         node->Flags |= ANF_VISIT;
  378.  
  379.         /* Check each assign in a multiassign */
  380.         FOREACHNODE( &node->Path, pathNode, next )
  381.         {
  382.             /* Do we have a parent that is ANF_STRAY? */
  383.             if( pathNode->Parent && ( ret = IsStray( pathNode->Parent ) ) )
  384.             {
  385.                 /* We found out what we wanted, so stop */
  386.                 break;
  387.             }
  388.         }
  389.  
  390.         if( ret > 0 )
  391.         {
  392.             node->Flags |= ANF_STRAY;
  393.         }
  394.         else if( ret < 0 )
  395.         {
  396.             /* Loop detected! */
  397.             node->Flags |= ANF_LOOP;
  398.         }
  399.  
  400.         /* Clear the visit flag. */
  401.         node->Flags &= ~ANF_VISIT;
  402.     }
  403.  
  404.     return( ret );
  405. }
  406.  
  407.  
  408. /* Handle any PATHADDs for the current node. Returns FALSE if it
  409.  * couldn't allocate the needed memory to do the "conversion".
  410.  */
  411. BOOL
  412. DoPathAdd( struct AssignNode *node )
  413. {
  414.     struct PathNode    *pathNode, *next;
  415.     STRPTR    newName;
  416.     LONG    count = 0, len = PathStartLen + 2;
  417.     BOOL    havePath = FALSE, success = TRUE;
  418.  
  419.     /* Get total string size needed, and find out if we have any "Path:".
  420.      * Also check number of targets.
  421.      */
  422.     FOREACHNODE( &node->Path, pathNode, next )
  423.     {
  424.         if( !Strnicmp( pathNode->Name, PathStart, PathStartLen ) )
  425.         {
  426.             havePath = TRUE;
  427.             strcpy( pathNode->Name, pathNode->Name + PathStartLen );
  428.         }
  429.  
  430.         len += strlen( pathNode->Name );
  431.         ++count;
  432.     }
  433.  
  434.     /* There are paths to be added to the first one. */
  435.     if( havePath )
  436.     {
  437.         if( ( newName = AllocVec( len + count, MEMF_ANY ) ) )
  438.         {
  439.             struct PathNode    *firstPath = ( struct PathNode * )
  440.                 RemHead( ( struct List * ) &node->Path );
  441.             STRPTR    work;
  442.  
  443.             /* Copy header to new name */
  444.             work = stpcpy( newName, PathStart );
  445.             work = stpcpy( work, firstPath->Name );
  446.  
  447.             /* Remove and copy old paths to the new one */
  448.             FOREACHNODE( &node->Path, pathNode, next )
  449.             {
  450.                 *work = PathAddChar;
  451.                 ++work;
  452.                 work = stpcpy( work, pathNode->Name );
  453.                 /* Free the old PathNode */
  454.                 FreePathNode( pathNode );
  455.             }
  456.  
  457.  
  458.             FreeVec( firstPath->Name );
  459.             firstPath->Name = newName;
  460.             /* Reinit list and add new node */
  461.             NewList( ( struct List * ) &node->Path );
  462.             AddHead( ( struct List * ) &node->Path, ( struct Node * ) firstPath );
  463.         }
  464.         else
  465.         {
  466.             success = FALSE;
  467.         }
  468.     }
  469.  
  470.     return( success );
  471. }
  472.  
  473.  
  474. /* This function traverses the AssignList, sets the Flags and Parent fields for all nodes.
  475.  * Also handles '/' chars in the beginning of names and PATHADDs.
  476.  * This is so that the AssignList() function knows when to try to do an assign.
  477.  * Also makes some validity checking.
  478.  * Returns FALSE if a PATHADD failed (it might need to reallocate some memory).
  479.  */
  480. BOOL
  481. PrepareAssignList( struct MinList *list )
  482. {
  483.     struct AssignNode    *node, *next;
  484.     LONG    count;
  485.     BOOL    success = TRUE;
  486.  
  487.     /* First pass. Set Parent and Flags (ANF_STRAY) for all nodes.
  488.      * Check for multiple targets for ANF_DEFER or ANF_PATH.
  489.      * Remove leading '/' chars (moving such nodes to the top of the Path list).
  490.      */
  491.     FOREACHNODE( list, node, next )
  492.     {
  493.         struct PathNode *pathNode, *nextPath;
  494.         STRPTR    colon;
  495.         TEXT    oldChar;
  496.  
  497.         /* Handle '/' chars */
  498.         {
  499.             struct PathNode    *firstPath = NULL;
  500.  
  501.             /* Check for '/' chars in the beginning of targets. */
  502.             FOREACHNODE( &node->Path, pathNode, nextPath )
  503.             {
  504.                 if( *pathNode->Name == '/' )
  505.                 {
  506.                     firstPath = pathNode;
  507.                     strcpy( pathNode->Name, pathNode->Name + 1 );
  508.                 }
  509.             }
  510.  
  511.             if( firstPath )
  512.             {
  513.                 Remove( ( struct Node * ) firstPath );
  514.                 AddHead( ( struct List * ) &node->Path, ( struct Node * ) firstPath );
  515.             }
  516.         }
  517.  
  518.         if( node->Flags & ANF_PATHADD )
  519.         {
  520.             /* Merge PATHADDs into a single string */
  521.             if( !( success = DoPathAdd( node ) ) )
  522.             {
  523.                 break;
  524.             }
  525.         }
  526.  
  527.         count = 0;
  528.  
  529.         /* Check each assign in a multiassign */
  530.         FOREACHNODE( &node->Path, pathNode, nextPath )
  531.         {
  532.             ++count;
  533.  
  534.             if( ( colon = strchr( pathNode->Name, ':' ) ) )
  535.             {
  536.                 ++colon;
  537.                 oldChar = *colon;
  538.                 *colon = 0;
  539.             }
  540.  
  541.             /* Do we have a parent? */
  542.             if( ( pathNode->Parent = FindAssignNode( list, pathNode->Name ) ) )
  543.             {
  544.                 node->Flags |= ANF_NODE;
  545.             }
  546.             /* Does the node refer to a not yet known volume? */
  547.             else if( ( node->AssignType == ASN_NORMAL ) &&
  548.                 !HaveProc( pathNode->Name ) )
  549.             {
  550.                 node->Flags |= ANF_STRAY;
  551.             }
  552.  
  553.             if( colon )
  554.             {
  555.                 *colon = oldChar;
  556.             }
  557.         }
  558.  
  559.         if( ( node->AssignType != ASN_NORMAL ) &&
  560.             ( node->AssignType != ASN_CMDPATH ) &&
  561.             ( ( count > 1 ) || ( node->Flags & ANF_ADD ) ) )
  562.         {
  563.             node->Flags |= ANF_BAD;    /* PATH of DEFER assigns can't be multiple. */
  564.         }
  565.  
  566.         /* Did we find any unresolved link? */
  567.         if( !( node->Flags & ( ANF_NODE | ANF_STRAY | ANF_BAD ) ) )
  568.         {
  569.             node->Flags |= ANF_VOLUME;    /* No */
  570.         }
  571.     }
  572.  
  573.     /* Second pass. Set ANF_STRAY for nodes whos parent have ANF_STRAY set.
  574.      * Also sets ANF_LOOP, if a loop is detected.
  575.      */
  576.     FOREACHNODE( list, node, next )
  577.     {
  578.         IsStray( node );
  579.     }
  580.  
  581.     return( success );
  582. }
  583.  
  584.  
  585. /* Do the assign for this node. Handles all different cases.
  586.  * Creates the needed drawers.
  587.  */
  588. BOOL
  589. AssignNode( struct AssignNode *node )
  590. {
  591.     BOOL    success = TRUE;
  592.  
  593.     if( !Test )
  594.     {
  595.         struct PathNode    *pathNode, *next;
  596.         STRPTR    colon;
  597.         BOOL    assignLock = TRUE;    /* If TRUE, call AssignLock() for the first node in Path. */
  598.         BPTR    target;            /* Lock of target drawer */
  599.  
  600.         /* Check if we should add to an existing assign. */
  601.         if( ( node->Flags & ANF_ADD ) && HaveProc( node->Name ) )
  602.         {
  603.             assignLock = FALSE;
  604.         }
  605.  
  606.         if( ( node->AssignType == ASN_CMDPATH ) && !( node->Flags & ANF_ADD ) )
  607.         {
  608.             ClearProcPath();
  609.         }
  610.  
  611.         /* Remove any colon in the assign name. */
  612.         if( ( colon = strchr( node->Name, ':' ) ) )
  613.         {
  614.             *colon = 0;
  615.         }
  616.  
  617.         FOREACHNODE( &node->Path, pathNode, next )
  618.         {
  619.             switch( node->AssignType )
  620.             {
  621.                 case ASN_PATH:
  622.                     success = AssignPath( node->Name, pathNode->Name );
  623.                     break;
  624.  
  625.                 case ASN_DEFER:
  626.                     success = AssignLate( node->Name, pathNode->Name );
  627.                     break;
  628.  
  629.                 case ASN_CMDPATH:
  630.                     /* Try to create the target */
  631.                     CreateDirPath( pathNode->Name );
  632.                     success = AddNameProcPath( pathNode->Name );
  633.                     break;
  634.  
  635.                 default:
  636.                     success = FALSE;
  637.  
  638.                     /* Try to create the target (may fail for e.g. path assings) */
  639.                     CreateDirPath( pathNode->Name );
  640.  
  641.                     /* And lock the target... */
  642.                     if( ( target = Lock( pathNode->Name, SHARED_LOCK ) ) )
  643.                     {
  644.                         /* Fire! :) */
  645.                         if( assignLock )
  646.                         {
  647.                             success = AssignLock( node->Name, target );
  648.                             assignLock = FALSE;
  649.                         }
  650.                         else
  651.                         {
  652.                             success = AssignAdd( node->Name, target );
  653.                         }
  654.  
  655.                         /* A miss. Unlock target again.. :) */
  656.                         if( !success )
  657.                         {
  658.                             UnLock( target );
  659.                         }
  660.                     }
  661.  
  662.                     break;
  663.             }
  664.  
  665.             if( !success )
  666.             {
  667.                 node->Flags |= ANF_FAILED;
  668.                 node->IoErr = IoErr();
  669.                 break;      /* Terminate loop */
  670.             }
  671.         }
  672.  
  673.         if( colon )
  674.         {
  675.             *colon = ':';
  676.         }
  677.     }
  678.  
  679.     if( success )
  680.     {
  681.         node->Flags |= ANF_ASSIGNED;
  682.  
  683.         if( !Test && ( node->AssignType != ASN_CMDPATH ) && node->Alias )
  684.         {
  685.             SetComment( node->Name, node->Alias );
  686.         }
  687.     }
  688.  
  689.     return( success );
  690. }
  691.  
  692.  
  693. /* Again some strings to save space... */
  694. const TEXT Mount_Msg[] = "C:Mount %s\n";
  695. const TEXT Nil_Msg[] = "Nil:";
  696.  
  697. /* Mount the device found in name. */
  698. LONG
  699. MountAssign( STRPTR name )
  700. {
  701.     LONG    success = 0;
  702.  
  703.     if( !Test )
  704.     {
  705.         /* Check if this volume already have been mounted */
  706.         if( !HaveProc( name ) )
  707.         {
  708.             STRPTR    command, colon;
  709.             TEXT    oldChar;
  710.  
  711.             success = -1;
  712.  
  713.             /* Remove anything after the colon */
  714.             if( ( colon = strchr( name, ':' ) ) )
  715.             {
  716.                 ++colon;
  717.                 oldChar = *colon;
  718.                 *colon = 0;
  719.             }
  720.  
  721.             if( ( command = AllocVec( sizeof( Mount_Msg ) + strlen( name ), MEMF_ANY ) ) )
  722.             {
  723.                 BPTR    in;
  724.  
  725.                 RawDoFmt( Mount_Msg, &name, ( VOID (*) ) "\x16" "\xc0" "\x4e" "\x75", command );
  726.  
  727.                 if( ( in = Open( Nil_Msg, MODE_OLDFILE ) ) )
  728.                 {
  729.                     BPTR    out;
  730.  
  731.                     if( ( out = Open( Nil_Msg, MODE_OLDFILE ) ) )
  732.                     {
  733.                         if( Verbose )
  734.                         {
  735.                             Printf( "BindNamesII: Mounting volume \"%s\"\n", ( LONG ) name );
  736.                         }
  737.  
  738.                         success = SystemTags( command,
  739.                             SYS_Input,  in,
  740.                             SYS_Output, out,
  741.                         TAG_DONE );
  742.  
  743.                         Close( out );
  744.                     }
  745.  
  746.                     Close( in );
  747.                 }
  748.  
  749.                 FreeVec( command );
  750.             }
  751.  
  752.             if( colon )
  753.             {
  754.                 *colon = oldChar;
  755.             }
  756.         }
  757.     }
  758.  
  759.     return( success );
  760. }
  761.  
  762.  
  763. /* Handle the assign for one node. This includes checking if a node
  764.  * have unassigned parents, in which case that assign is delayed.
  765.  * The assign is placed on the proper list.
  766.  */
  767. VOID
  768. HandleAssign(
  769.     struct MinList        *list,
  770.     struct MinList        *assigned,
  771.     struct MinList        *failed,
  772.     struct AssignNode    *node )
  773. {
  774.     struct PathNode    *pathNode, *next;
  775.     BOOL    asn = TRUE, fail = FALSE;
  776.  
  777.     /* Check if all parents for this node have been assigned. */
  778.     FOREACHNODE( &( node->Path ), pathNode, next )
  779.     {
  780.         /* Do we have a parent? */
  781.         if( pathNode->Parent )
  782.         {
  783.             /* Yes, check if it is assigned already */
  784.             if( !( pathNode->Parent->Flags & ANF_ASSIGNED ) )
  785.             {
  786.                 asn = FALSE;
  787.             }
  788.  
  789.             /* Did the assing fail (second check mostly for speed.. :)? */
  790.             if( ( pathNode->Parent->Flags & ANF_FAILED ) ||
  791.                 ( pathNode->Parent->Flags & ANF_BADPARENT ) )
  792.             {
  793.                 fail = TRUE;
  794.                 node->Flags |= ANF_BADPARENT;
  795.             }
  796.         }
  797.     }
  798.  
  799.     /* If the parents have been assigned, then assign this one too. */
  800.     if( asn )
  801.     {
  802.         if( AssignNode( node ) )
  803.         {
  804.             AddTail( ( struct List * ) assigned, ( struct Node * ) node );
  805.         }
  806.         else
  807.         {
  808.             AddTail( ( struct List * ) failed, ( struct Node * ) node );
  809.         }
  810.     }
  811.     else
  812.     {
  813.         if( fail )
  814.         {
  815.             /* A parent failed, so this must fail too */
  816.             AddTail( ( struct List * ) failed, ( struct Node * ) node );
  817.         }
  818.         else
  819.         {
  820.             /* Retry this node later on */
  821.             AddTail( ( struct List * ) list, ( struct Node * ) node );
  822.         }
  823.     }
  824. }
  825.  
  826.  
  827. /* Go trough the list and do all assigns in the proper order.
  828.  * Returns FALSE if some assigns failed.
  829.  * NOTE: The list is freed by this function!
  830.  */
  831. BOOL
  832. AssignList( struct MinList *list )
  833. {
  834.     struct AssignNode   *node;
  835.     struct MinList      assigned;    /* Holds the assigned volumes */
  836.     struct MinList      failed;    /* Holds the assigns that failed */
  837.     struct MinList      stray;    /* Temporary list for stray nodes. */
  838.     BOOL    success = TRUE;
  839.  
  840.     /* Init all lists. */
  841.     NewList( ( struct List * ) &assigned );
  842.     NewList( ( struct List * ) &failed );
  843.     NewList( ( struct List * ) &stray );
  844.  
  845.     /* First pass. Do all assigns to existing volumes,
  846.      * or to other assigns that refers to existing volumes (etc).
  847.      * Move stray and path nodes to the proper list for later processing.
  848.      */
  849.     while( ( node = ( struct AssignNode * ) RemHead( ( struct List * ) list ) ) )
  850.     {
  851.         if( node->Flags & ANF_STRAY )
  852.         {
  853.             /* These needs mounting, handled later */
  854.             AddTail( ( struct List * ) &stray, ( struct Node * ) node );
  855.         }
  856.         else if( node->Flags & ( ANF_LOOP | ANF_BAD ) )
  857.         {
  858.             /* Remove known bad nodes */
  859.             AddTail( ( struct List * ) &failed, ( struct Node * ) node );
  860.         }
  861.         else if( node->Flags & ANF_VOLUME )
  862.         {
  863.             /* This volume should be assignable */
  864.             if( AssignNode( node ) )
  865.             {
  866.                 AddTail( ( struct List * ) &assigned, ( struct Node * ) node );
  867.             }
  868.             else
  869.             {
  870.                 AddTail( ( struct List * ) &failed, ( struct Node * ) node );
  871.             }
  872.         }
  873.         else
  874.         {
  875.             /* This node have other node(s) as parent(s) */
  876.             HandleAssign( list, &assigned, &failed, node );
  877.         }
  878.     }
  879.  
  880.     /* Second pass. Try to mount all volumes that needs it. */
  881.     while( ( node = ( struct AssignNode * ) RemHead( ( struct List * ) &stray ) ) )
  882.     {
  883.         struct PathNode    *pathNode, *next;
  884.  
  885.         FOREACHNODE( &node->Path, pathNode, next )
  886.         {
  887.             if( !pathNode->Parent )
  888.             {
  889.                 /* Try to mount the volume it refers to. Ignore any errors,
  890.                  * since the mount might take a little while. Thus, the
  891.                  * "dupe mount checking" in MountAssign() might not notice
  892.                  * a previous Mount. Or so I suspect.. :)
  893.                  * I don't know enough about Mount internals... :/
  894.                  */
  895.                 MountAssign( pathNode->Name );
  896.             }
  897.         }
  898.  
  899.         AddTail( ( struct List * ) list, ( struct Node * ) node );
  900.     }
  901.  
  902.     /* Third pass. Do the rest of the assigns, those that needed a
  903.      * mount first. No stray nodes to handle, all "bad" nodes are
  904.      * gone. We still need to check for unassigned parents though,
  905.      */
  906.     while( ( node = ( struct AssignNode * ) RemHead( ( struct List * ) list ) ) )
  907.     {
  908.         HandleAssign( list, &assigned, &failed, node );
  909.     }
  910.  
  911.     if( Verbose )
  912.     {
  913.         if( IsListEmpty( ( struct List * ) &assigned ) )
  914.         {
  915.             Printf( "BindNamesII:\nNo assigns made\n" );
  916.         }
  917.         else
  918.         {
  919.             Printf( "BindNamesII:\nAssigns:\n" );
  920.             PrintAssignList( &assigned );
  921.         }
  922.     }
  923.  
  924.     if( !( IsListEmpty( ( struct List * ) &failed ) || Quiet ) )
  925.     {
  926.         if( !Verbose )
  927.         {
  928.             Printf( "BindNamesII:" );
  929.         }
  930.  
  931.         Printf( "\nUnresolved assigns:\n" );
  932.         PrintAssignList( &failed );
  933.         success = FALSE;
  934.     }
  935.  
  936.     FreeAssignList( &assigned );
  937.     FreeAssignList( &failed );
  938.     return( success );
  939. }
  940.  
  941.  
  942. #ifdef __GNUC__
  943. int main( VOID )
  944. #else
  945. LONG _main( VOID )
  946. #endif
  947. {
  948.     struct RDArgs   *rdArg;
  949.     struct Flags    flags;
  950.     struct Window   *window;
  951.     struct Process  *thisTask;
  952.     LONG    code = RETURN_FAIL; /* A bit pessimistic perhaps, but it saves some code! :) */
  953.  
  954.     /* Disable volume requesters */
  955.     thisTask = ( struct Process * ) FindTask( NULL );
  956.     window = thisTask->pr_WindowPtr;
  957.     thisTask->pr_WindowPtr = ( struct Window * ) -1;
  958.  
  959.     bzero( &flags, sizeof( flags ) );
  960.     flags.Drawer = "Sys:Names";
  961.  
  962.     if( ( rdArg = ReadArgs( TEMPLATE, ( LONG * ) &flags, NULL ) ) )
  963.     {
  964.         struct MinList  assignList;
  965.  
  966.         NewList( ( struct List * ) &assignList );
  967.  
  968.         if( flags.Test )
  969.         {
  970.             Test = TRUE;
  971.         }
  972.  
  973.         if( flags.Verbose )
  974.         {
  975.             Verbose = TRUE;
  976.         }
  977.  
  978.         if( flags.Quiet )
  979.         {
  980.             Quiet = TRUE;
  981.         }
  982.  
  983.         if( flags.PathAddChar )
  984.         {
  985.             PathAddChar = *flags.PathAddChar;
  986.         }
  987.  
  988.         if( flags.PathStart )
  989.         {
  990.             PathStart = flags.PathStart;
  991.             PathStartLen = strlen( PathStart );
  992.         }
  993.  
  994.         if( ScanDrawer( flags.Drawer, &assignList ) )
  995.         {
  996.             if( !PrepareAssignList( &assignList ) )
  997.             {
  998.                 PrintNoMem();
  999.             }
  1000.             else
  1001.             {
  1002.                 if( AssignList( &assignList ) )
  1003.                 {
  1004.                     code = RETURN_OK;
  1005.                 }
  1006.                 else
  1007.                 {
  1008.                     code = RETURN_WARN;
  1009.                 }
  1010.             }
  1011.         }
  1012.         else
  1013.         {
  1014.             FreeAssignList( &assignList );
  1015.         }
  1016.  
  1017.         FreeArgs( rdArg );
  1018.     }
  1019.     else
  1020.     {
  1021.         PrintError( "Error in arguments" );
  1022.     }
  1023.  
  1024.     thisTask->pr_WindowPtr = window;
  1025.     return( code );
  1026. }
  1027.